package cn.edu.hitsz.compiler.parser;

import cn.edu.hitsz.compiler.NotImplementedException;
import cn.edu.hitsz.compiler.lexer.Token;
import cn.edu.hitsz.compiler.parser.table.Production;
import cn.edu.hitsz.compiler.parser.table.Status;
import cn.edu.hitsz.compiler.symtab.SourceCodeType;
import cn.edu.hitsz.compiler.symtab.SymbolTable;

import javax.management.Attribute;
import java.util.Objects;
import java.util.Stack;

// TODO: 实验三: 实现语义分析
public class SemanticAnalyzer implements ActionObserver {

    private SymbolTable symbolTable;

    // 本来准备直接用String的, 为了增加一点拓展性, 改用了Attribute
    private final Stack<Attribute> attrs = new Stack<>();

    @Override
    public void whenAccept(Status currentStatus) {
        // TODO: 该过程在遇到 Accept 时要采取的代码动作
        // 没什么好做的
    }

    @Override
    public void whenReduce(Status currentStatus, Production production) {
        // TODO: 该过程在遇到 reduce production 时要采取的代码动作
        switch (production.index()) {
            case 4 -> { // S -> D id;
                String id = attrs.pop().getName();
                String type = attrs.pop().getName();
                if (symbolTable.has(id)) {
                    symbolTable.get(id).setType(SourceCodeType.Int);
                } else {
                    throw new RuntimeException("id not in table");
                }
                attrs.push(new Attribute(id, null));
            }
            case 5 -> { // D -> int
                // D的attr和int的attr在同一个位置, 不变即可
                // 或者可以说先pop再push
            }
            default -> {
                // 弹出属性, 节省栈空间
                for (int i = 0; i < production.body().size() - 1; i++) {
                    attrs.pop();
                }
            }
        }
    }

    @Override
    public void whenShift(Status currentStatus, Token currentToken) {
        // TODO: 该过程在遇到 shift 时要采取的代码动作
        // 将变量名, 变量类型等都移入栈
        attrs.push(new Attribute(currentToken.getText(), null));
    }

    @Override
    public void setSymbolTable(SymbolTable table) {
        // TODO: 设计你可能需要的符号表存储结构
        // 如果需要使用符号表的话, 可以将它或者它的一部分信息存起来, 比如使用一个成员变量存储
        symbolTable = table;
    }

    public SymbolTable getSymbolTable() {
        return symbolTable;
    }
}

